package com.lg.cms.utils;

import com.baomidou.mybatisplus.extension.api.R;
import com.sun.javafx.collections.MappingChange;
import io.swagger.models.auth.In;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: 统计信息工具类
 * @Author: wuyuhang
 * @create: 2020-09-23 22:43
 * 使用以下方法初始化对象
 * @Resource
 * StatsUtils statsUtils;
 */
@Component
public class StatsUtil {

    @Resource
    RedisUtil redisUtil;
    /**
     * 获取文章点赞数
     * @param articleId (文章id)
     * @return 点赞数
     */
    public Integer getArticleLike(Integer articleId){
        Integer num = (int) redisUtil.sGetSetSize("cms:article_like:" + articleId.toString());
        if(num == null){
            num = 0;
        }
        return num;
    }

    /**
     * 获取文章浏览量
     * @param articleId (文章id)
     * @return 浏览量
     */
    public Integer getArticleView(Integer articleId){
        Integer num = (Integer) redisUtil.get("cms:article_view_count:" + articleId.toString());
        if(num == null){
            num = 0;
            redisUtil.set("cms:article_view_count:" + articleId.toString(), 0);
        }
        return num;
    }
    /**
     * 用户点赞文章
     * @param articleId (文章id)
     * @param userId (用户id)
     * @return R<?>
     */
    public R<?> addArticleLike(Integer articleId, Long userId){
        Set<Object> idSet = redisUtil.sGet("cms:article_like:" + articleId.toString());
        if(idSet.contains(userId)){
            return R.failed("您以点过赞了");
        }else{
            redisUtil.sSet("cms:article_like:" + articleId.toString(), userId);
            return R.ok(null);
        }

    }

    /**
     * 用户取消点赞
     * @param articleId (用户id)
     * @param userId (用户id)
     * @return R<?>
     */
    public R<?> deleteArticleLike(Integer articleId, Long userId){
        Set<Object> idSet = redisUtil.sGet("cms:article_like:" + articleId.toString());
        if(idSet.contains(userId)){
            return R.failed("您未点赞过此文章");
        }else{
            redisUtil.setRemove("cms:article_like:" + articleId.toString(), userId);
            return R.ok(null);
        }
    }

    /**
     * 新增访问量, 根据ip地址, 最多一个ip一天计算一次访问量
     * @param articleId (文章id)
     * @param ip (用户ip地址)
     */
    public void addArticleView(Integer articleId, String ip){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Set<Object> idSet = redisUtil.sGet("cms:article_view:" + articleId.toString());
        Object objectViewMap = redisUtil.get("cms:article_view_map");
        Integer dayViewNum = (Integer) redisUtil.get("cms:dayViewNum:" + sdf.format(date));
        if(dayViewNum == null){
            dayViewNum = 0;
        }
//        List<Integer> viewSort = new ArrayList<>();
        Map<Integer, Integer> viewMap = new HashMap<>();
        if(objectViewMap != null){
            viewMap = (Map<Integer, Integer>) objectViewMap;
        }
        Integer viewCount = (Integer) redisUtil.get("cms:article_view_count:" + articleId.toString());
        if(viewCount == null){
            viewCount = 0;
        }
        if(!idSet.contains(ip)){

            viewCount += 1;
            viewMap.put(articleId, viewCount);
            redisUtil.sSetAndTime("cms:article_view:" + articleId.toString(), 60*60*24, ip);
            redisUtil.set("cms:article_view_count:" + articleId.toString(), viewCount);
            redisUtil.set("cms:article_view_map", viewMap);  //更新文章id对应浏览量集合
            redisUtil.set("cms:dayViewNum:" + sdf.format(date), dayViewNum);
//            System.out.println("文章:" + articleId + ", 浏览量+1");
            System.out.println("文章:" + articleId + ", 浏览量+1, ip为:" + ip);
        }
    }

    /**
     * 获取当天文章总访问量
     * @return Num
     */
    public Integer getAllViewNum(){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Integer dayViewNum = (Integer) redisUtil.get("cms:dayViewNum:" + sdf.format(date));
        if(dayViewNum == null){
            dayViewNum = 0;
        }
        return dayViewNum;
    }

    /**
     * 判断用户是否点赞了此文章
     * @param articleId
     * @param userId
     * @return
     */
    public Boolean isLike(Integer articleId, Long userId){
        Set<Object> idSet = redisUtil.sGet("cms:article_like:" + articleId.toString());
        return idSet.contains(userId);
    }

    /**
     * 获取浏览量从高到低文章id列表, 参数为获取的数量
     * @param count
     * @return
     */
    public List<Integer> getTopArticleId(Integer count){
        List<Integer> articleIdList = new ArrayList<>();
        List<C> cList = new ArrayList<>();
        Object objectViewMap = redisUtil.get("cms:article_view_map");
        if(objectViewMap == null){
            return articleIdList;
        }
        Map<Object, Integer> map = (Map<Object, Integer>)objectViewMap;

        for(Map.Entry<Object, Integer> entry: map.entrySet()){
//            System.out.println("key:" + entry.getKey() + ", value:" + entry.getValue());
//            System.out.println("key-class:" + entry.getKey().getClass());
//            System.out.println("value-class:" + entry.getValue().getClass());
            cList.add(new C(Integer.valueOf(String.valueOf(entry.getKey())), entry.getValue()));
        }
        cList.sort(C::compareTo);//排序
        try{
            cList =  cList.subList(0, count);
        }catch (Exception e){
        }
        cList.forEach(v -> articleIdList.add(v.getArticleId()));

        System.out.println("\n浏览量最高的文章列表: ");
        System.out.print("[");
        for(C c : cList){
            System.out.print("(" + c.getArticleId() + ", " + c.getViewNum() + "), ");
        }
        System.out.print("]\n");
        return articleIdList;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private class C implements Comparable<C>{
        private Integer articleId;
        private Integer viewNum;

        /**
         * 重写排序方法
         * @param o
         * @return
         */
        @Override
        public int compareTo(C o) {
//            return this.viewNum - o.viewNum;//升序
            return o.viewNum - this.viewNum;//升序
        }
    }
}